package com.example.socket.schema;

import com.example.socket.client.ClientConfig;
import com.example.socket.client.ClientDispatcher;
import com.example.socket.client.ClientFactory;
import com.example.socket.codec.Coder;
import com.example.socket.codec.JProtocolCoder;
import com.example.socket.codec.JsonCoder;
import com.example.socket.codec.MessageConvertor;
import com.example.socket.filter.CleanIdleFilter;
import com.example.socket.filter.DebugFilter;
import com.example.socket.filter.ManagementFilter;
import com.example.socket.filter.firewall.FirewallFilter;
import com.example.socket.filter.session.*;
import com.example.socket.filter.transitory.DelayedPushListener;
import com.example.socket.handler.Dispatcher;
import com.example.socket.handler.NettyHandler;
import com.example.socket.handler.ParameterBuilder;
import com.example.socket.properties.FirewallProperties;
import com.example.socket.properties.PackageScanProperties;
import com.example.socket.properties.SocketProperties;
import com.example.socket.server.GameServer;
import com.example.socket.server.ServerConfig;
import com.example.socket.server.ServerDispatcher;
import io.netty.channel.Channel;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

/**
 * @author frank
 * @date 2019-03-09 14:23
 * @desc
 **/
@Configuration
@EnableConfigurationProperties({SocketProperties.class, PackageScanProperties.class})
public class SocketAutoConfiguration {

    @Resource
    private SocketProperties socketProperties;
    @Resource
    private PackageScanProperties packageScanProperties;

    @Bean
    public RegisterFactory getBeanFactory() {
        //核心的指令注册工厂
        return new RegisterFactory(registerBuilder(), packageScanProperties);
    }

    @Bean
    public MessageConvertor registerMessageConvertor() {
        //Message转换器
        Map<Byte, Coder> coders = getCoders();
        return new MessageConvertor(coders);
    }

    @Bean
    public ParameterBuilder registerBuilder() {
        //参数解析器
        return new ParameterBuilder(registerMessageConvertor());
    }


    private Map<Byte, Coder> getCoders() {
        //自定义coder
        Map<Byte, Coder> coders = new HashMap<>();
        coders.put((byte) 0, new JProtocolCoder());
        coders.put((byte) 1, new JsonCoder());
        return coders;
    }

    @Bean
    public SessionFactory<Channel> registerSessionFactory() {
        //维护Session的工厂类
        return new NettySessionFactory();
    }

    @Bean(name = "server-dispatcher")
    public Dispatcher registerServerDispatcher() {
        ServerDispatcher serverDispatcher = new ServerDispatcher();
        if (socketProperties.getServer().isTransitory()) {
            //短连接监听器
            TransientSessionListener transientSessionListener = new TransientSessionListener();
            transientSessionListener.setDispatcher(serverDispatcher);
            //子监听器
            DelayedPushListener delayedPushListener = new DelayedPushListener();
            delayedPushListener.setDispatcher(serverDispatcher);
            //添加子监听器
            transientSessionListener.addListener(delayedPushListener);
            serverDispatcher.addListener(transientSessionListener);
        }
        return serverDispatcher;
    }

    @Bean
    public SessionManager registerSessionManager() {
        //注册Session管理器
        NettySessionManager sessionManager = new NettySessionManager();
        sessionManager.setSessionFactory(registerSessionFactory());
        sessionManager.setDispatcher(registerServerDispatcher());
        sessionManager.setDelayTime(socketProperties.getServer().getSessionDelayDestroy());
        return sessionManager;
    }

    @Bean
    public SessionManagerFilter registerSessionManagerFilter() {
        SessionManagerFilter sessionManagerFilter = new SessionManagerFilter();
        return sessionManagerFilter.setSessionManager(registerSessionManager());
    }

    @Bean
    public ManagementFilter registerManagementFilter() {
        ManagementFilter managementFilter = new ManagementFilter();
        managementFilter.setAllowIpConfig(socketProperties.getServer().getFilter().getAllowIps());
        return managementFilter;
    }

    @Bean
    public CleanIdleFilter registerCleanIdleFilter() {
        CleanIdleFilter cleanIdleFilter = new CleanIdleFilter();
        cleanIdleFilter.setTimeoutSeconds(socketProperties.getServer().getTimeout());
        return cleanIdleFilter;
    }

    @Bean
    public FirewallFilter registerFirewallFilter() {
        FirewallProperties firewallProperties = socketProperties.getServer().getFirewall();
        FirewallFilter firewallFilter = new FirewallFilter();
        firewallFilter.setAllows(firewallProperties.getAllows());
        firewallFilter.setBlock(firewallProperties.getBlocks());
        firewallFilter.setBlockAllState(firewallProperties.getAutostartBlock());
        firewallFilter.setBlockTimes(firewallProperties.getBlockTimes());
        firewallFilter.setMaxClients(firewallProperties.getMaxClient());
        firewallFilter.setBytesInSecondLimit(firewallProperties.getRecvBytesLimitPerSecond());
        firewallFilter.setTimesInSecondLimit(firewallProperties.getRecvPackagesLimitPerSecond());
        firewallFilter.setMaxViolateTimes(firewallProperties.getFaultTolerant());
        return firewallFilter;
    }

    @Bean
    public DebugFilter registerDebugFilter() {
        return new DebugFilter();
    }

    @Bean
    public NettyHandler registerNettyHandler() {
        return new NettyHandler(registerServerDispatcher());
    }

    @Bean
    public GameServer registerGameServer() {
        GameServer gameServer = new GameServer();
        gameServer.setHandler(registerNettyHandler());
        return gameServer;
    }

    @Bean
    public ServerConfig registerServerConfig() {
        ServerConfig serverConfig = new ServerConfig(socketProperties.getServer());
        return serverConfig;
    }

    @Bean
    public SocketInitializer registerSocketInitializer() {
        SocketInitializer socketInitializer = new SocketInitializer();
        socketInitializer.setConfig(registerServerConfig());
        socketInitializer.setGameServer(registerGameServer());
        socketInitializer.setSessionManager(registerSessionManager());
        return socketInitializer;
    }

    //client register

    @Bean
    public ClientConfig registerClientConfig() {
        ClientConfig clientConfig = new ClientConfig(socketProperties.getClient());
        return clientConfig;
    }

    @Bean(name = "client-dispatcher")
    public ClientDispatcher registerClientDispatcher() {
        ClientDispatcher clientDispatcher = new ClientDispatcher();
        return clientDispatcher;
    }

    @Bean
    public ClientFactory registerClientFactory() {
        return new ClientFactory(registerClientConfig(),
                registerClientDispatcher(), null);
    }
}
